#include "esp_log.h"
#include "driver/gpio.h"

#include "hal/gpio_types.h"
#include "user_ch9329.h"
#include "user_hid.h"
#include "user_nvs.h"
#include "user_hid_control.h"
#include "crc.h"

static const char *TAG = "[HID]";

/*******************指示灯驱动********************/
#define KEYBOARD_LED_PIN_SEL (1ULL<<GPIO_NUM_8)
void fun_light_init()
{
    gpio_config_t io_config = {
        .intr_type = GPIO_INTR_DISABLE,
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = KEYBOARD_LED_PIN_SEL,
        .pull_down_en = 1,
        .pull_up_en = 0
    };
    gpio_config(&io_config);
    gpio_set_level(GPIO_NUM_8, 1);
}
void fun_light_ctl(bool flag){gpio_set_level(GPIO_NUM_8, flag ? 0 : 1);}
/************************************************/

typedef struct {
    uint8_t fun_code;   // 功能预留([0]: 1按下 0抬起; [1]: 0按键类型 1延时类型)
    uint16_t ctl_data;  // 如果是按键类型取后8位作为hid码，如果是延时类型最大65535ms
} __attribute__((__packed__)) key_ctl_data;

#define KEY_LOCAL_STR "key_list"

/*************************esc计时控制*****************************/
static uint32_t time_s = 0;
uint32_t time_s_target = 0;
TimerHandle_t esc_timer_handle; // esc按键定时器句柄
/////////////////
TaskHandle_t esc_handle;
TaskHandle_t key_handle;

void esc_timer_callback(TimerHandle_t xTimer)
{
    time_s++;
}

void esc_timer_init()
{
    // 读取预存延时数据
    uint8_t h = 0, m = 0, s = 0;
    if(user_nvs_u8_get("h", &h) != ESP_OK ||
        user_nvs_u8_get("m", &m) != ESP_OK ||
        user_nvs_u8_get("s", &s) != ESP_OK){
        ESP_LOGW(TAG, "get time data error");
    }
    time_s_target = s + (60 * m) + (60 * 60 * h);
     
    // 创建定时器（1s）
    int32_t esc_timer_id = 0;   
    esc_timer_handle = xTimerCreate("esc_timer", 
                                    pdMS_TO_TICKS(1000), 
                                    pdTRUE, 
                                    (void*)esc_timer_id, 
                                    esc_timer_callback);
    xTimerStart(esc_timer_handle, pdMS_TO_TICKS(100));
}

void esc_task()
{
    static bool wait = true;
    while(true){
        if(time_s > time_s_target && wait){
            // 关闭定时器、执行esc操作、阻塞
            xTimerStop(esc_timer_handle, pdMS_TO_TICKS(100));

            // test(HID_KEY_ESCAPE);
            test(HID_KEY_ESCAPE);

            wait = false;
        }
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void esc_task_start()
{
    xTaskCreate(esc_task, 
                "esc_task", 
                2048, 
                NULL, 
                10, 
                &esc_handle);
}
/************************************************************************/

/*************************宏控制*****************************/
static uint16_t action_index = 0;   // 当前行为索引
TimerHandle_t wait_key_timer_handle;    // 等待宏按键定时器
key_ctl_data test_data[4] = {
    {
        .fun_code = 0x1,
        .ctl_data = HID_KEY_A
    },
    {
        .fun_code = 0x2,
        .ctl_data = 500
    },
    {
        .fun_code = 0x0,
        .ctl_data = HID_KEY_A
    },
    {
        .fun_code = 0x2,
        .ctl_data = 500
    }
};
key_ctl_data* key_local_buff = NULL;
uint8_t key_ctl_size = 0;

void key_ctl(key_ctl_data ctl_pack)
{
    if((ctl_pack.fun_code & (1 << 1)) == 0){
        // 按键类型
        ch9329_update_key_status(ctl_pack.ctl_data & 0xFF, (ctl_pack.fun_code & 1) ? true : false);
    } else{
        // 延时类型
        vTaskDelay(pdMS_TO_TICKS(ctl_pack.ctl_data));
    }
}

void carry_out_key_list()
{
    if(key_ctl_size == 0 || key_local_buff == NULL) return;
    key_ctl(key_local_buff[action_index]);   // 调用对应功能
    action_index++;
    if(action_index > key_ctl_size){
        action_index = 0;
    }
}

void key_ctl_task()
{
    uint8_t save_data[13] = {0};
    memcpy(save_data, (const void*)test_data, 12);
    save_data[12] = crc8_maxim(save_data, 12);
    user_nvs_array_set(KEY_LOCAL_STR, (const void*)save_data, 13);
    size_t key_local_len = user_nvs_array_len_get(KEY_LOCAL_STR);
    if(key_local_len % sizeof(key_ctl_data) == 1 && key_local_len > 1){ // 有校验码形式
        // 读取所有信息
        uint8_t* nvs_get_buff = (uint8_t*)malloc(key_local_len);
        memset(nvs_get_buff, 0, key_local_len);
        user_nvs_array_get(KEY_LOCAL_STR, (uint8_t*)nvs_get_buff, key_local_len);
        if(crc8_maxim(nvs_get_buff, key_local_len - 1) ==
            nvs_get_buff[key_local_len - 1]){
            // 校验通过
            key_local_buff = (key_ctl_data*)malloc(key_local_len - 1);
            memcpy(key_local_buff, nvs_get_buff, key_local_len - 1);
            free(nvs_get_buff);
            key_ctl_size = (key_local_len - 1) / sizeof(key_ctl_data);
        } else{
            ESP_LOGW(TAG, "crc error: %x != %x", crc8_maxim(nvs_get_buff, key_local_len - 1), nvs_get_buff[key_local_len - 1]);
            free(nvs_get_buff);
        }
        
        vTaskDelay(pdMS_TO_TICKS(100));
    } else{
        ESP_LOGW(TAG, "nvs data invalid");
    }
    while(true){
        /****该写法有风险，若有连续大量按键操作没有延时可能导致线程阻塞死机****/
        carry_out_key_list();
    }
}

void hid_control_start()
{
    // 初始化灯
    fun_light_init();
    // 启动esc线程
    esc_timer_init();
    esc_task_start();

    // 启动宏按键线程
    xTaskCreate(key_ctl_task, 
                "key_ctl_task", 
                2048, 
                NULL, 
                10, 
                &key_handle);
    
    fun_light_ctl(true);
    // 先挂起任务等待外部触发
    vTaskDelay(pdMS_TO_TICKS(50));
    suspend_hid_control();
}

// 检测任务是否运行
bool task_is_running()
{
    eTaskState task_state = eTaskGetState(key_handle);
    return (task_state == eRunning || 
            task_state == eReady || 
            task_state == eBlocked);
}

// 挂起任务
void suspend_hid_control()
{
    // 获取任务状态
    eTaskState esc_task_state = eTaskGetState(esc_handle);
    if(esc_task_state == eRunning || 
        esc_task_state == eReady || 
        esc_task_state == eBlocked){
        vTaskSuspend(esc_handle);
    }

    eTaskState key_task_state = eTaskGetState(key_handle);
    if(key_task_state == eRunning || 
        key_task_state == eReady ||
        key_task_state == eBlocked){
        vTaskSuspend(key_handle);
    }

    ch9329_clear_key_status();  // 清空按键状态

    fun_light_ctl(false);
}

// 恢复任务
void resume_hid_control()
{
    // 获取任务状态
    eTaskState esc_task_state = eTaskGetState(esc_handle);
    if(esc_task_state == eSuspended){
        vTaskResume(esc_handle);
    }

    eTaskState key_task_state = eTaskGetState(key_handle);
    if(key_task_state == eSuspended){
        vTaskResume(key_handle);
    }

    ch9329_clear_key_status();  // 清空按键状态

    fun_light_ctl(true);
}
